﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Mvc;

namespace rossisdead.Mvc.Detergent
{
    public class CascadingActionResult : ActionResult
    {
        #region Properties

        /// <summary>
        /// Gets or sets the data to be converted to a collection of SelectListItems.
        /// </summary>
        public IEnumerable Data { get; set; }

        /// <summary>
        /// Gets or sets the JsonRequestBehavior used for this result.
        /// </summary>
        public JsonRequestBehavior JsonRequestBehavior { get; set; }

        /// <summary>
        /// Gets or sets the selected value in the Data.
        /// </summary>
        public object SelectedValue { get; set; }

        /// <summary>
        /// Gets or sets the property that should be used for the text field.
        /// </summary>
        public string TextField { get; set; }

        /// <summary>
        /// Gets or sets the property that should be used for the value field.
        /// </summary>
        public string ValueField { get; set; }

        #endregion

        #region Constructors

        public CascadingActionResult() { }

        public CascadingActionResult(IEnumerable data)
        {
            Data = data;
        }

        public CascadingActionResult(IEnumerable data, string textField, string valueField)
            : this(data)
        {
            TextField = textField;
            ValueField = valueField;
        }

        #endregion

        #region Private Methods

        /// <summary>
        /// Creates an ActionResult that represents the json output for use with ExecuteResult.
        /// </summary>
        /// <returns></returns>
        internal protected virtual ActionResult CreateJsonResult()
        {
            var json = new JsonResult();
            json.Data = GetJsonItems();
            json.JsonRequestBehavior = JsonRequestBehavior;
            return json;
        }

        #endregion


        /// <summary>
        /// Returns the SelectListItems created from the given Data.
        /// </summary>
        /// <returns></returns>
        public virtual IEnumerable<SelectListItem> GetSelectListItems()
        {
            if (Data == null)
            {
                throw new ArgumentNullException("Data");
            }
            // Creating a SelectList instance to allow it to do the parsing of 
            // each item to a SelectListItem. Easier than reimplementing it ourselves.
            var list = new SelectList(Data, ValueField, TextField, SelectedValue);

            if (list.Any())
            {
                // We need to return the empty selected value prompt.
                // We don't add this if there aren't any items because we're assuming
                // that the select list will be in "disabled" mode in this case.
                //
                // Selected is set up this way, as opposed to throwing an exception, to match
                // what SelectList does internally(ie, it ignores the selected value if it's
                // not found in the list).
                yield return new SelectListItem { Value = "", Text = "-- Select --", Selected = list.SelectedValue == null };
            }
            foreach (var item in list)
            {
                yield return item;
            }
        }

        /// <summary>
        /// Returns anonymous object versions of the items returned from GetSelectListItems.
        /// This is to reduce clutter when rendered to json.
        /// </summary>
        /// <returns></returns>
        public virtual IEnumerable<object> GetJsonItems()
        {
            // We're recreating the select list item objects for json results
            // because we don't want to send back more than we need. ie: we
            // don't need to send back a selected value attribute for
            // all of the json results.

            foreach (var item in GetSelectListItems())
            {
                if (item.Selected)
                {
                    System.Diagnostics.Debug.Print("Selected: " + item.Value);
                    yield return new { value = item.Value, text = item.Text, selected = true };
                }
                else
                {
                    yield return new { value = item.Value, text = item.Text };
                }
            }
        }

        /// <summary>
        /// Executes the CascadingActionResult as a JsonResult.
        /// </summary>
        /// <param name="context"></param>
        public override void ExecuteResult(ControllerContext context)
        {
            CreateJsonResult().ExecuteResult(context);
        }
    }
}
